package com.xf.system.common.facade;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xf.system.utils.excel.ExcelUtil;
import com.xf.system.common.model.User;
import com.xf.system.common.model.UserDept;
import com.xf.system.common.model.UserRole;
import com.xf.system.common.service.*;
import com.xf.system.constants.DateConst;
import com.xf.system.enums.GenderEnum;
import com.xf.system.enums.StatusEnum;
import com.xf.system.exception.BusinessException;
import com.xf.system.exception.Errors;
import com.xf.system.http.req.user.*;
import com.xf.system.http.vo.user.*;
import com.xf.system.utils.date.DateUtils;
import com.xf.system.utils.StringUtil.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author xiefengf
 */
@Service
@Slf4j
public class UserFacade {

    @Resource
    private UserService userService;

    @Resource
    private DeptService deptService;

    @Resource
    private RoleService roleService;

    @Resource
    private UserDeptService userDeptService;

    @Resource
    private UserRoleService userRoleService;

    /**
     * 根据条件分页查询用户列表
     *
     * @param reqDto 分页信息+查询条件
     * @return 用户分页集合信息
     */
    public UserVO listUsers(UserListReqDTO reqDto) {
        // 1、获取分页条件查询的数据
        IPage<UserDetailVO> iPage = userService.selectUserPage(reqDto);
        // 2、封装数据
        UserVO userVo = new UserVO();
        List<UserDetailVO> userDetailVoList = iPage.getRecords().stream().peek(x -> {
            // 设置用户性别和帐号状态的中文显示名称
            x.setGenderName(GenderEnum.getByName(x.getGender()).getName());
            x.setStatusName(StatusEnum.getByName(x.getStatus()).getName());
            x.setDeptList(new ArrayList<>());
            x.setRoleList(new ArrayList<>());
            x.setPostList(new ArrayList<>());
        }).collect(Collectors.toList());
        userVo.setUserDetailVoList(userDetailVoList);
        userVo.setCurrent(iPage.getCurrent());
        userVo.setSize(iPage.getSize());
        userVo.setPages(iPage.getPages());
        userVo.setTotal(iPage.getTotal());
        // 3、返回数据
        return userVo;
    }

    /**
     * 通过用户id查询用户详情信息
     *
     * @param id 用户id
     * @return 用户详情信息
     */
    public UserDetailVO getUserById(Long id) {
        // 1、查询当前用户信息
        UserDetailVO userDetailVo = userService.selectUserByUid(id);
        // 设置用户性别和帐号状态的中文显示名称
        userDetailVo.setGenderName(GenderEnum.getByName(userDetailVo.getGender()).getName());
        userDetailVo.setStatusName(StatusEnum.getByName(userDetailVo.getStatus()).getName());
        // 2、查询当前用户对应的部门信息
        List<UserDeptDetailVO> deptDetailVoList = deptService.selectDeptByUid(id);
        if (CollectionUtils.isEmpty(deptDetailVoList)){
            deptDetailVoList = new ArrayList<>();
        }
        // 3、查询当前用户对应的角色信息
        List<UserRoleDetailVO> roleDetailVoList = roleService.selectRoleByUid(id);
        if (CollectionUtils.isEmpty(roleDetailVoList)){
            roleDetailVoList = new ArrayList<>();
        }
        // 4、查询当前用户对应的岗位信息
        // TODO: 2024/2/2 查询岗位表，获取当前用户的岗位信息

        // 5、封装数据
        userDetailVo.setDeptList(deptDetailVoList);
        userDetailVo.setRoleList(roleDetailVoList);
        userDetailVo.setPostList(new ArrayList<>());
        // 6、返回数据
        return userDetailVo;
    }

    /**
     * 新增用户信息
     *
     * @param reqDto 用户信息
     * @return 执行结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveUser(UserAddReqDTO reqDto) {
        // 1、校验数据 登录账号/手机号码/邮箱 在数据库中唯一
        // 1.1 校验登录账户在数据库中唯一
        User userByUserName = userService.selectUserByUserName(reqDto.getUserName());
        if (StringUtils.isNotNull(userByUserName)){
            // 登录账号已存在
            throw new BusinessException(Errors.System.SYSTEM_01001);
        }
        // 1.2 校验手机号码在数据库中唯一
        User userByPhone = userService.selectUserByPhone(reqDto.getPhoneNumber());
        if (StringUtils.isNotNull(userByPhone)){
            // 手机号码已存在
            throw new BusinessException(Errors.System.SYSTEM_01002);
        }
        // 1.3 校验邮箱在数据库中唯一
        User userByEmail = userService.selectUserByEmail(reqDto.getEmail());
        if (StringUtils.isNotNull(userByEmail)){
            // 邮箱账号已存在
            throw new BusinessException(Errors.System.SYSTEM_01003);
        }
        // 2、保存用户数据
        User user = new User();
        // TODO: 2024/2/2 密码加密
        BeanUtils.copyProperties(reqDto,user);
        boolean saveUser = userService.save(user);
        boolean saveUserDept = Boolean.TRUE;
        boolean saveUserRole = Boolean.TRUE;
        boolean saveUserPost = Boolean.TRUE;
        Long id = user.getId();
        // 3、保存用户-部门关联信息
        if (!CollectionUtils.isEmpty(reqDto.getDeptIdList())){
            List<UserDept> deptList = new ArrayList<>();
            for (Long deptId : reqDto.getDeptIdList()) {
                UserDept userDept = new UserDept(id,deptId);
                deptList.add(userDept);
            }
            saveUserDept = userDeptService.saveBatch(deptList);
        }
        // 4、保存用户-角色关联信息
        if (!CollectionUtils.isEmpty(reqDto.getRoleIdList())){
            List<UserRole> roleList = new ArrayList<>();
            for (Long roleId : reqDto.getRoleIdList()) {
                UserRole userRole = new UserRole(id,roleId);
                roleList.add(userRole);
            }
            saveUserRole = userRoleService.saveBatch(roleList);
        }
        // 5、保存用户-岗位关联信息
        // TODO: 2024/2/2 保存用户-岗位关联信息

        return saveUser && saveUserDept && saveUserRole && saveUserPost;
    }

    /**
     * 更新用户信息
     *
     * @param reqDto 用户信息
     * @return 执行结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUser(UserUpdateReqDTO reqDto) {
        // 用户id
        Long id = reqDto.getId();
        // 1、校验数据 手机号码/邮箱 在数据库中唯一
        // 1.1 校验手机号码在数据库中唯一，且不是当前用户
        User userByPhone = userService.selectUserByPhone(reqDto.getPhoneNumber());
        if (StringUtils.isNotNull(userByPhone) && !id.equals(userByPhone.getId())){
            // 手机号码已存在
            throw new BusinessException(Errors.System.SYSTEM_01002);
        }
        // 1.2 校验邮箱在数据库中唯一，且不是当前用户
        User userByEmail = userService.selectUserByEmail(reqDto.getEmail());
        if (StringUtils.isNotNull(userByEmail) && !id.equals(userByEmail.getId())){
            // 邮箱账号已存在
            throw new BusinessException(Errors.System.SYSTEM_01003);
        }
        // 2、更新用户
        User user = new User();
        BeanUtils.copyProperties(reqDto,user);
        boolean updateUser = userService.updateById(user);
        boolean updateUserDept = Boolean.TRUE;
        boolean updateUserRole = Boolean.TRUE;
        boolean updateUserPost = Boolean.TRUE;
        // 3、更新用户-部门关联信息（先删再新增）
        if (!CollectionUtils.isEmpty(reqDto.getDeptIdList())){
            // 删除用户与部门关联
            userDeptService.deleteUserDeptByUid(id);
            // 新增用户与部门关联
            List<UserDept> deptList = new ArrayList<>();
            for (Long deptId : reqDto.getDeptIdList()) {
                UserDept userDept = new UserDept(id,deptId);
                deptList.add(userDept);
            }
            updateUserDept = userDeptService.saveBatch(deptList);
        }
        // 4、更新用户-角色关联信息（先删再新增）
        if (!CollectionUtils.isEmpty(reqDto.getRoleIdList())){
            // 删除用户与角色关联
            userRoleService.deleteUserRoleByUid(id);
            // 新增用户与角色关联
            List<UserRole> roleList = new ArrayList<>();
            for (Long roleId : reqDto.getRoleIdList()) {
                UserRole userRole = new UserRole(id,roleId);
                roleList.add(userRole);
            }
            updateUserRole = userRoleService.saveBatch(roleList);
        }
        // 5、更新用户-岗位关联信息（先删再新增）
        // TODO: 2024/2/2  更新用户-岗位关联信息（先删再新增）

        return updateUser && updateUserDept && updateUserRole && updateUserPost;
    }

    /**
     * 批量删除用户信息
     *
     * @param idList 用户id列表
     * @return 执行结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteUser(Long[] idList) {
        // TODO: 2024/2/2 相关校验

        List<Long> userIdList = Arrays.stream(idList).collect(Collectors.toList());
        // 1、删除用户表数据
        boolean removeUser = userService.removeByIds(userIdList);
        // 2、删除用户与部门关联
        userDeptService.deleteUserDeptByUidList(userIdList);
        // 3、删除用户与角色关联
        userRoleService.deleteUserRoleByUidList(userIdList);
        // 4、删除用户与岗位关联
        // TODO: 2024/2/2  删除用户与岗位关联

        return removeUser;
    }

    /**
     * 重置用户密码
     *
     * @param reqDto 用户id+旧密码+新密码
     * @return 执行结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean resetPwd(UserResetPwdReqDTO reqDto){
        // 1、根据用户id查询用户信息
        User user = userService.getById(reqDto.getId());
        if (StringUtils.isNull(user)){
            // 当前用户不存在
            throw new BusinessException(Errors.System.SYSTEM_01004);
        }
        if (!reqDto.getOldPassword().equals(user.getPassword())){
            // 旧密码输入有误
            throw new BusinessException(Errors.System.SYSTEM_01005);
        }
        // 2、更新密码
        // TODO: 2024/2/2 密码加密
        user.setPassword(reqDto.getNewPassword());
        return userService.updateById(user);
    }

    /**
     * 用户状态修改
     *
     * @param reqDto 用户id+账户状态
     * @return 执行结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean changeStatus(UserChangeStatusReqDTO reqDto){
        // 1、根据用户id查询用户信息
        User user = userService.getById(reqDto.getId());
        if (StringUtils.isNull(user)){
            // 当前用户不存在
            throw new BusinessException(Errors.System.SYSTEM_01004);
        }
        // 2、更新密码
        user.setStatus(reqDto.getStatus());
        return userService.updateById(user);
    }

    /**
     * 模版下载
     * @param response 响应对象
     */
    public void downloadImportTemplate(HttpServletResponse response) {
        // 下载用户模板文件
        ExcelUtil.downloadTemplate(UserExcelTemplateVO.class,"用户模板",response,"用户");
    }

    /**
     * 导入用户数据
     * @param file 文件对象
     */
    @Transactional(rollbackFor = Exception.class)
    public void importExcel(MultipartFile file) {
        // 解析excel
        List<UserExcelTemplateVO> excelData = ExcelUtil.importExcel(file,UserExcelTemplateVO.class);
        // 用户账号唯一性校验，用户账号作为唯一标识，有则更新，没有则心中
        Map<String,Integer> existUserNameInExcelMap = new HashMap<>();
        // 查询数据库中已存在的用户账号
        List<User> userList = userService.list();
        Map<String, Long> userNameMap = userList.stream().collect(Collectors.toMap(User::getUserName, User::getId, (k1, k2) -> k1));
        //最终列表
        List<User> saveList = new ArrayList<>();
        List<User> updateList = new ArrayList<>();
        //遍历处理
        Integer row = 1;
        for(UserExcelTemplateVO vo : excelData){
            // 必填校验
            ExcelUtil.verifyStringIsNotBlank(vo.getUserName(),"用户账号",row);
            ExcelUtil.verifyStringIsNotBlank(vo.getPhoneNumber(),"手机号码",row);
            // 长度校验
            ExcelUtil.verifyStringLength(vo.getUserName(),"用户账号",128,row);
            ExcelUtil.verifyStringLength(vo.getPhoneNumber(),"手机号码",11,row);
            // 用户账号重复校验
            if (existUserNameInExcelMap.containsKey(vo.getUserName())){
                Long lastRowIndex = userNameMap.get(vo.getUserName());
                throw new BusinessException(9999,"第"+lastRowIndex+"，"+row+"行用户账号重复");
            }else{
                existUserNameInExcelMap.put(vo.getUserName(),row);
            }
            // 类型转换
            User user = new User();
            BeanUtils.copyProperties(vo,user);
            // 日期转换
            user.setLoginDate(DateUtils.stringToDate(vo.getLoginDate(), DateConst.SHORT));
            //id赋值
            if(userNameMap.containsKey(vo.getUserName())){
                user.setId(userNameMap.get(vo.getUserName()));
                updateList.add(user);
            }else {
                saveList.add(user);
            }
            row++;
        }
        // 保存或更新数据
        if (!CollectionUtils.isEmpty(saveList)){
            userService.saveBatch(saveList);
        }
        if (!CollectionUtils.isEmpty(updateList)){
            userService.updateBatchById(updateList);
        }
    }

    /**
     * 导出用户数据
     * @param reqDto 查询条件
     */
    public void exportExcel(HttpServletResponse response,UserListReqDTO reqDto) {
        // 查询用户数据
        List<UserDetailVO> userList = userService.selectUserList(reqDto);
        // 数据处理
        List<UserExcelTemplateVO> list = new ArrayList<>();
        for (UserDetailVO userDetailVO : userList) {
            UserExcelTemplateVO vo = new UserExcelTemplateVO();
            BeanUtils.copyProperties(userDetailVO,vo);
            // 格式转换
            vo.setLoginDate(DateUtils.dateToString(userDetailVO.getLoginDate(), DateConst.SHORT));
            list.add(vo);
        }
        // 导出用户数据
        ExcelUtil.exportExcel(response,UserExcelTemplateVO.class,list,"用户数据","用户");
    }


}
